package com.penghe.www.baselibrary.utils

import android.graphics.Bitmap
import com.penghe.www.baselibrary.utils.LogUtil
import java.util.*


/**
 * Created by alm on 17-6-1.
 * 内存缓存工具类
 */

class MemoryCache {

    init {
        // use 25% of available heap size
        setLimit(Runtime.getRuntime().maxMemory() / 4)
    }

    companion object {
        /**
         * 日志打印的TAG
         */
        private val TAG: String = "MemoryCache"
    }

    /**
     * 放入缓存时是个同步操作
     * LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列，即LRU
     * 这样的好处是如果要将缓存中的元素替换，则先遍历出最近最少使用的元素来替换以提高效率
     */
    private val cache: MutableMap<String, Bitmap> = java.util.Collections.synchronizedMap(LinkedHashMap<String, Bitmap>(20, 1.5f, true))

    /**
     * 缓存中图片所占用的字节，初始0，将通过此变量严格控制缓存所占用的堆内存
     */
    private var size: Long = 0// current allocated size

    /**
     * 缓存只能占用的最大堆内存
     */
    private var mLimit: Long = 1000000// max memory in bytes ,单位：byte

    //自定义函数

    /**
     * 从链表里获取图片
     *
     * @param key 链表对应的key
     * @return 位图图片
     */
    fun get(key: String): Bitmap? {
        if (!cache.containsKey(key)) {
            return null
        }
        return cache[key]
    }

    /**
     * 往链表里添加一张图片
     *
     * @param key 链表对应的key
     * @param bitmap  位图图片
     */
    fun put(key: String, bitmap: Bitmap) {
        if (cache.containsKey(key)) {
            size -= getSizeInBytes(cache[key])
        }
        cache.put(key, bitmap)
        size += getSizeInBytes(bitmap)
        checkSize()
    }

    /**
     * 清除缓存
     */
    fun clear() {
        cache.clear()
    }

    //自定义内部私有函数

    /**
     * 设置内存可用大小
     *
     * @param limit 内存可用大小
     */
    private fun setLimit(limit: Long) {
        mLimit = limit
    }

    /**
     * 严格控制堆内存，如果超过将首先替换最近最少使用的那个图片缓存
     */
    private fun checkSize() {
        LogUtil.w(TAG, "cache size=" + size + " length=" + cache.size)
        if (size > mLimit) {
            // 先遍历最近最少使用的元素
            val iterator = cache.entries.iterator()
            while (iterator.hasNext()) {
                val entry = iterator.next()
                size -= getSizeInBytes(entry.value)
                iterator.remove()
                if (size <= mLimit) {
                    break
                }
            }
            LogUtil.w(TAG, "Clean cache. New size " + cache.size)
        }
    }

    /**
     * 获取图片占用的内存
     *
     * @param bitmap 位图图片
     * @return 图片占用的内存大小
     */
    private fun getSizeInBytes(bitmap: Bitmap?): Long {
        if (bitmap == null) {
            return 0
        }
        return (bitmap.rowBytes * bitmap.height).toLong()
    }
}